//----------------------------------Include-------------------------------------
#include "mcu.h"
//------------------------------------------------------------------------------

//------------------------------------Type--------------------------------------
typedef struct{
  uint32_t  sys_clk;
  uint32_t  hclk;
  uint32_t  pclk1;
  uint32_t  pclk2;
  uint32_t  pclk3;
  uint32_t  pclk4;
}t_clk;
//------------------------------------------------------------------------------

//-----------------------------------Macro--------------------------------------
//内部时钟
#define HSI                 (64000000)
#define HSI48               (48000000)
#define LSI                    (32000)
#define CSI                  (4000000)
//外部时钟
#define HSE                 (25000000)    //4-48MHz
#define LSE                    (32768)
//------------------------------------------------------------------------------

//--------------------------------Static Var------------------------------------
static t_clk                 nt_clk;
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
void mcu_sys_clock(void)
{
  RCC_ClkInitTypeDef    RCC_ClkInitStruct;
  RCC_OscInitTypeDef    RCC_OscInitStruct;
  HAL_StatusTypeDef     ret = HAL_OK;

  //锁住SCU(Supply configuration update)
  MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);

  //1、芯片内部的LDO稳压器输出的电压范围，可选VOS1，VOS2和VOS3，不同范围对应不同的Flash读速度，详情看参考手册的Table 12的表格
  //2、这里选择使用VOS1，电压范围1.15V - 1.26V。
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  //使能HSE，并选择HSE作为PLL时钟源
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState       = RCC_HSE_ON;
  RCC_OscInitStruct.HSIState       = RCC_HSI_OFF;
  RCC_OscInitStruct.CSIState       = RCC_CSI_OFF;
  RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource  = RCC_PLLSOURCE_HSE;
    
  RCC_OscInitStruct.PLL.PLLM = 5;
  RCC_OscInitStruct.PLL.PLLN = 160;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
    
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLRGE    = RCC_PLL1VCIRANGE_2;
  ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
  if(ret != HAL_OK){ while(1); }
  
  //选择PLL的输出作为系统时钟
  //配置 RCC_CLOCKTYPE_SYSCLK 系统时钟
  //配置 RCC_CLOCKTYPE_HCLK  时钟，对应AHB1，AHB2，AHB3和AHB4总线
  //配置 RCC_CLOCKTYPE_PCLK1 时钟，对应APB1总线
  //配置 RCC_CLOCKTYPE_PCLK2 时钟，对应APB2总线
  //配置 RCC_CLOCKTYPE_D1PCLK1 时钟，对应APB3总线
  //配置 RCC_CLOCKTYPE_D3PCLK1 时钟，对应APB4总线
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK  | RCC_CLOCKTYPE_HCLK  |
                                 RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 |
                                 RCC_CLOCKTYPE_PCLK2   | RCC_CLOCKTYPE_D3PCLK1);

  RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider  = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider  = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
  
  //此函数会更新 SystemCoreClock，并重新配置 HAL_InitTick
  uwTickPrio = TICK_INT_PRIORITY;   //提高优先级，否则 HAL_RCC_ClockConfig 里调用 HAL_InitTick 会失败
  ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
  if(ret != HAL_OK){ while(1); }
  
  //使用IO的高速模式，要使能IO补偿，即调用下面三个函数 
  //（1）使能 CSI clock
  //（2）使能 SYSCFG clock
  //（3）使能I/O补偿单元， 设置 SYSCFG_CCCSR 寄存器的bit0
  __HAL_RCC_CSI_ENABLE() ;
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  HAL_EnableCompensationCell();

  //AXI SRAM的时钟是上电自动使能的，而D2域的SRAM1，SRAM2和SRAM3要单独使能
#if 1
  __HAL_RCC_D2SRAM1_CLK_ENABLE();
  __HAL_RCC_D2SRAM2_CLK_ENABLE();
  __HAL_RCC_D2SRAM3_CLK_ENABLE();
#endif
  
  nt_clk.sys_clk = RCC_GetSystemClockFreq();
  nt_clk.hclk    = RCC_GetHCLKClockFreq(nt_clk.sys_clk);
  nt_clk.pclk1   = RCC_GetPCLK1ClockFreq(nt_clk.hclk);
  nt_clk.pclk2   = RCC_GetPCLK2ClockFreq(nt_clk.hclk);
  nt_clk.pclk3   = RCC_GetPCLK3ClockFreq(nt_clk.hclk);
  nt_clk.pclk4   = RCC_GetPCLK4ClockFreq(nt_clk.hclk);
}
//------------------------------------------------------------------------------
uint32_t  mcu_get_sys_clk(void) { return nt_clk.sys_clk;  }
uint32_t  mcu_get_hclk(void)    { return nt_clk.hclk;     }
uint32_t  mcu_get_pclk1(void)   { return nt_clk.pclk1;    }
uint32_t  mcu_get_pclk2(void)   { return nt_clk.pclk2;    }
uint32_t  mcu_get_pclk3(void)   { return nt_clk.pclk3;    }
uint32_t  mcu_get_pclk4(void)   { return nt_clk.pclk4;    }
//------------------------------------EOF---------------------------------------





